#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os
import cv2
import numpy as np
import time
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap, QImage, QFont
from PyQt5.QtCore import QTimer, pyqtSignal, QThread, Qt

# 尝试导入OCR模块
try:
    from paddleocr import PaddleOCR
    OCR_AVAILABLE = True
except ImportError:
    OCR_AVAILABLE = False
    print("Warning: PaddleOCR not available. Install with: pip install paddleocr")

# 添加上级目录到Python路径以导入MvImport模块
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from MvImport.MvCameraControl_class import *
from MvImport.MvErrorDefine_const import *
from MvImport.PixelType_header import *

class CameraThread(QThread):
    """相机线程"""
    image_ready = pyqtSignal(np.ndarray)  # 图像数据信号
    binary_ready = pyqtSignal(np.ndarray)  # 二值化图像信号
    exposure_changed = pyqtSignal(float)  # 曝光时间变化信号
    fps_updated = pyqtSignal(float)  # 帧率更新信号
    number_detected = pyqtSignal(str, float)  # 数字识别结果信号
    
    def __init__(self, camera_index=0):
        super().__init__()
        self.camera_index = camera_index
        self.is_running = False
        self.cam = None
        self.current_exposure = 10000.0  # 默认曝光时间（微秒）
        self.frame_count = 0
        self.last_fps_time = time.time()
        self.fps = 0.0
        self.binary_method = "adaptive"  # 二值化方法
        
        # 初始化OCR
        self.ocr = None
        self.init_ocr()
        
    def init_ocr(self):
        """初始化OCR"""
        if OCR_AVAILABLE:
            try:
                self.ocr = PaddleOCR(use_angle_cls=True, lang='en', show_log=False)
                print("OCR初始化成功")
            except Exception as e:
                print(f"OCR初始化失败: {e}")
                self.ocr = None
        else:
            print("OCR不可用")
        
    def run(self):
        """运行相机"""
        try:
            # 枚举设备
            deviceList = MV_CC_DEVICE_INFO_LIST()
            tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
            
            ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)
            if ret != 0 or deviceList.nDeviceNum == 0:
                print("没有找到设备!")
                return
                
            if self.camera_index >= deviceList.nDeviceNum:
                print(f"设备索引 {self.camera_index} 超出范围!")
                return
            
            # 创建相机实例
            self.cam = MvCamera()
            
            # 选择设备并创建句柄
            stDeviceList = cast(deviceList.pDeviceInfo[self.camera_index], POINTER(MV_CC_DEVICE_INFO)).contents
            
            ret = self.cam.MV_CC_CreateHandle(stDeviceList)
            if ret != 0:
                print(f"创建句柄失败! ret[0x{ret:08x}]")
                return
                
            # 打开设备
            ret = self.cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
            if ret != 0:
                print(f"打开设备失败! ret[0x{ret:08x}]")
                self.cam.MV_CC_DestroyHandle()
                return
            
            # 设置触发模式为off
            ret = self.cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
            if ret != 0:
                print(f"设置触发模式失败! ret[0x{ret:08x}]")
            
            # 设置曝光时间
            ret = self.cam.MV_CC_SetFloatValue("ExposureTime", self.current_exposure)
            if ret != 0:
                print(f"设置曝光时间失败! ret[0x{ret:08x}]")
            else:
                print(f"曝光时间设置为: {self.current_exposure} 微秒")
            
            # 开始取流
            ret = self.cam.MV_CC_StartGrabbing()
            if ret != 0:
                print(f"开始取流失败! ret[0x{ret:08x}]")
                self.cam.MV_CC_CloseDevice()
                self.cam.MV_CC_DestroyHandle()
                return
            
            print("相机开始采集...")
            self.is_running = True
            
            # 获取图像数据
            stOutFrame = MV_FRAME_OUT()
            memset(byref(stOutFrame), 0, sizeof(stOutFrame))
            
            while self.is_running:
                ret = self.cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
                if ret == 0:
                    # 转换图像数据
                    data = (c_ubyte * stOutFrame.stFrameInfo.nFrameLen)()
                    cdll.msvcrt.memcpy(byref(data), stOutFrame.pBufAddr, stOutFrame.stFrameInfo.nFrameLen)
                    
                    # 根据像素格式转换图像
                    if stOutFrame.stFrameInfo.enPixelType == PixelType_Gvsp_Mono8:
                        # 单色图像
                        img_data = np.frombuffer(data, dtype=np.uint8)
                        img = img_data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth))
                        img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
                    elif stOutFrame.stFrameInfo.enPixelType == PixelType_Gvsp_RGB8_Packed:
                        # RGB图像
                        img_data = np.frombuffer(data, dtype=np.uint8)
                        img = img_data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth, 3))
                        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
                    else:
                        # 其他格式，尝试转换为BGR
                        img_data = np.frombuffer(data, dtype=np.uint8)
                        img = img_data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth, -1))
                        if len(img.shape) == 2:
                            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
                    
                    # 计算帧率
                    self.frame_count += 1
                    current_time = time.time()
                    if current_time - self.last_fps_time >= 1.0:  # 每秒更新一次FPS
                        self.fps = self.frame_count / (current_time - self.last_fps_time)
                        self.fps_updated.emit(self.fps)
                        self.frame_count = 0
                        self.last_fps_time = current_time
                    
                    # 数字识别（每5帧识别一次）
                    if self.frame_count % 5 == 0 and self.ocr:
                        detected_number, confidence = self.recognize_numbers(img)
                        if detected_number:
                            self.number_detected.emit(detected_number, confidence)
                    
                    # 发送图像数据
                    self.image_ready.emit(img)
                    
                    # 生成二值化图像
                    binary_img = self.create_binary_image(img, self.binary_method)
                    self.binary_ready.emit(binary_img)
                    
                    # 释放图像缓存
                    self.cam.MV_CC_FreeImageBuffer(stOutFrame)
                else:
                    time.sleep(0.01)
                    
        except Exception as e:
            print(f"相机线程错误: {e}")
        finally:
            self.stop()
    
    def set_exposure(self, exposure_time):
        """设置曝光时间"""
        self.current_exposure = exposure_time
        if self.cam and self.is_running:
            ret = self.cam.MV_CC_SetFloatValue("ExposureTime", exposure_time)
            if ret == 0:
                self.exposure_changed.emit(exposure_time)
                print(f"曝光时间已更新为: {exposure_time} 微秒")
            else:
                print(f"设置曝光时间失败! ret[0x{ret:08x}]")
    
    def set_binary_method(self, method):
        """设置二值化方法"""
        self.binary_method = method
        print(f"二值化方法已更新为: {method}")
    
    def create_binary_image(self, image, method="adaptive"):
        """创建极简黑白二值化图像"""
        try:
            # 转换为灰度图
            if len(image.shape) == 3:
                gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            else:
                gray = image
            
            # 简单的二值化处理
            if method == "adaptive":
                # 自适应阈值 - 适合光照不均匀的情况
                binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
            elif method == "otsu":
                # OTSU - 自动计算最佳阈值
                _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
            elif method == "simple":
                # 简单阈值 - 固定阈值127
                _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
            elif method == "canny":
                # Canny边缘 - 只显示边缘
                binary = cv2.Canny(gray, 100, 200)
            else:
                # 默认使用简单阈值
                _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
            
            # 直接返回二值化图像（单通道）
            return binary
            
        except Exception as e:
            print(f"二值化错误: {e}")
            # 如果出错，返回灰度图
            if len(image.shape) == 3:
                return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            else:
                return image
    
    def recognize_numbers(self, image):
        """识别图像中的数字"""
        try:
            if self.ocr is None:
                return "", 0.0
            
            # 预处理图像以提高识别率
            # 转换为灰度图
            if len(image.shape) == 3:
                gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            else:
                gray = image
            
            # 增强对比度
            clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
            enhanced = clahe.apply(gray)
            
            # 降噪
            denoised = cv2.medianBlur(enhanced, 3)
            
            # OCR识别
            result = self.ocr.ocr(denoised, cls=True)
            
            if result and result[0]:
                best_number = ""
                best_confidence = 0.0
                
                for line in result[0]:
                    text = line[1][0].strip()
                    confidence = line[1][1]
                    
                    # 过滤纯数字
                    if text.isdigit() and len(text) <= 6:  # 最多6位数字
                        if confidence > best_confidence:
                            best_number = text
                            best_confidence = confidence
                
                return best_number, best_confidence
            
            return "", 0.0
            
        except Exception as e:
            print(f"数字识别错误: {e}")
            return "", 0.0
    
    def stop(self):
        """停止相机"""
        self.is_running = False
        if self.cam:
            try:
                self.cam.MV_CC_StopGrabbing()
                self.cam.MV_CC_CloseDevice()
                self.cam.MV_CC_DestroyHandle()
            except:
                pass

class SimpleCameraViewer(QMainWindow):
    """简单相机显示窗口"""
    
    def __init__(self):
        super().__init__()
        self.camera_thread = None
        self.fps_limit = None  # 帧率限制
        self.last_frame_time = 0  # 上一帧时间
        self.binary_method = "adaptive"  # 二值化方法
        self.init_ui()
        
    def init_ui(self):
        """初始化界面"""
        self.setWindowTitle('海康威视相机 - 图像显示')
        self.setGeometry(100, 100, 1000, 700)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QHBoxLayout()
        
        # 左侧：原始图像显示
        left_widget = QWidget()
        left_layout = QVBoxLayout(left_widget)
        
        # 原始图像标题
        original_title = QLabel("原始图像")
        original_title.setFont(QFont("Arial", 12, QFont.Bold))
        original_title.setAlignment(Qt.AlignCenter)
        left_layout.addWidget(original_title)
        
        # 原始图像显示标签
        self.image_label = QLabel()
        self.image_label.setMinimumSize(400, 300)
        self.image_label.setStyleSheet("border: 2px solid gray;")
        self.image_label.setText("等待连接相机...")
        self.image_label.setAlignment(Qt.AlignCenter)
        left_layout.addWidget(self.image_label)
        
        # 帧率显示标签（右上角）
        self.fps_label = QLabel("FPS: --")
        self.fps_label.setStyleSheet("""
            QLabel {
                background-color: rgba(0, 0, 0, 0.7);
                color: white;
                padding: 5px 10px;
                border-radius: 5px;
                font-weight: bold;
                font-size: 12px;
            }
        """)
        self.fps_label.setAlignment(Qt.AlignRight | Qt.AlignTop)
        self.fps_label.setFixedSize(80, 30)
        
        # 将帧率标签添加到图像标签上
        self.image_label.setLayout(QVBoxLayout())
        self.image_label.layout().addWidget(self.fps_label, 0, Qt.AlignRight | Qt.AlignTop)
        self.image_label.layout().setContentsMargins(10, 10, 10, 10)
        
        main_layout.addWidget(left_widget)
        
        # 右侧：二值化图像显示
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)
        
        # 二值化图像标题
        binary_title = QLabel("二值化图像")
        binary_title.setFont(QFont("Arial", 12, QFont.Bold))
        binary_title.setAlignment(Qt.AlignCenter)
        right_layout.addWidget(binary_title)
        
        # 二值化图像显示标签
        self.binary_label = QLabel()
        self.binary_label.setMinimumSize(400, 300)
        self.binary_label.setStyleSheet("border: 2px solid gray;")
        self.binary_label.setText("等待二值化...")
        self.binary_label.setAlignment(Qt.AlignCenter)
        right_layout.addWidget(self.binary_label)
        
        main_layout.addWidget(right_widget)
        
        # 创建垂直布局来容纳图像区域和控制面板
        vertical_layout = QVBoxLayout()
        vertical_layout.addLayout(main_layout)
        
        # 控制面板（底部）
        control_widget = QWidget()
        control_layout = QVBoxLayout(control_widget)
        
        # 控制按钮
        button_layout = QHBoxLayout()
        
        self.start_button = QPushButton("开始显示")
        self.start_button.setMinimumHeight(40)
        self.start_button.clicked.connect(self.start_camera)
        button_layout.addWidget(self.start_button)
        
        self.stop_button = QPushButton("停止显示")
        self.stop_button.setMinimumHeight(40)
        self.stop_button.clicked.connect(self.stop_camera)
        self.stop_button.setEnabled(False)
        button_layout.addWidget(self.stop_button)
        
        control_layout.addLayout(button_layout)
        
        # 二值化控制
        binary_group = QGroupBox("二值化控制")
        binary_layout = QVBoxLayout(binary_group)
        
        # 二值化方法选择
        binary_method_layout = QHBoxLayout()
        binary_method_label = QLabel("二值化方法:")
        binary_method_layout.addWidget(binary_method_label)
        
        self.binary_method_combo = QComboBox()
        self.binary_method_combo.addItems(["自适应阈值", "OTSU", "简单阈值", "Canny边缘"])
        self.binary_method_combo.currentTextChanged.connect(self.on_binary_method_changed)
        binary_method_layout.addWidget(self.binary_method_combo)
        
        binary_layout.addLayout(binary_method_layout)
        control_layout.addWidget(binary_group)
        
        # 曝光时间控制
        exposure_group = QGroupBox("曝光时间控制")
        exposure_layout = QVBoxLayout(exposure_group)
        
        # 曝光时间滑块
        self.exposure_slider = QSlider(Qt.Horizontal)
        self.exposure_slider.setMinimum(1000)  # 1毫秒
        self.exposure_slider.setMaximum(1000000)  # 1000毫秒 (1秒)
        self.exposure_slider.setValue(10000)  # 默认10毫秒
        self.exposure_slider.setTickPosition(QSlider.TicksBelow)
        self.exposure_slider.setTickInterval(100000)  # 每100毫秒一个刻度
        self.exposure_slider.valueChanged.connect(self.on_exposure_changed)
        exposure_layout.addWidget(self.exposure_slider)
        
        # 曝光时间显示标签
        self.exposure_label = QLabel("曝光时间: 10.0 毫秒")
        self.exposure_label.setAlignment(Qt.AlignCenter)
        exposure_layout.addWidget(self.exposure_label)
        
        # 快速设置按钮
        quick_buttons_layout = QHBoxLayout()
        
        self.auto_exposure_button = QPushButton("自动曝光")
        self.auto_exposure_button.clicked.connect(self.set_auto_exposure)
        quick_buttons_layout.addWidget(self.auto_exposure_button)
        
        self.short_exposure_button = QPushButton("短曝光")
        self.short_exposure_button.clicked.connect(self.set_short_exposure)
        quick_buttons_layout.addWidget(self.short_exposure_button)
        
        self.long_exposure_button = QPushButton("长曝光")
        self.long_exposure_button.clicked.connect(self.set_long_exposure)
        quick_buttons_layout.addWidget(self.long_exposure_button)
        
        self.ultra_long_exposure_button = QPushButton("超长曝光")
        self.ultra_long_exposure_button.clicked.connect(self.set_ultra_long_exposure)
        quick_buttons_layout.addWidget(self.ultra_long_exposure_button)
        
        self.extreme_exposure_button = QPushButton("极长曝光")
        self.extreme_exposure_button.clicked.connect(self.set_extreme_exposure)
        quick_buttons_layout.addWidget(self.extreme_exposure_button)
        
        exposure_layout.addLayout(quick_buttons_layout)
        control_layout.addWidget(exposure_group)
        
        # 状态信息
        status_group = QGroupBox("系统状态")
        status_layout = QVBoxLayout(status_group)
        
        self.status_label = QLabel("就绪")
        status_layout.addWidget(self.status_label)
        
        # 帧率控制
        fps_control_layout = QHBoxLayout()
        
        fps_limit_label = QLabel("帧率限制:")
        fps_control_layout.addWidget(fps_limit_label)
        
        self.fps_limit_combo = QComboBox()
        self.fps_limit_combo.addItems(["无限制", "30 FPS", "25 FPS", "20 FPS", "15 FPS", "10 FPS"])
        self.fps_limit_combo.currentTextChanged.connect(self.on_fps_limit_changed)
        fps_control_layout.addWidget(self.fps_limit_combo)
        
        status_layout.addLayout(fps_control_layout)
        
        # 性能信息
        self.performance_label = QLabel("性能: 正常")
        status_layout.addWidget(self.performance_label)
        
        control_layout.addWidget(status_group)
        
        # 数字识别结果显示
        recognition_group = QGroupBox("数字识别结果")
        recognition_layout = QVBoxLayout(recognition_group)
        
        self.recognition_label = QLabel("等待识别...")
        self.recognition_label.setFont(QFont("Arial", 14, QFont.Bold))
        self.recognition_label.setAlignment(Qt.AlignCenter)
        self.recognition_label.setStyleSheet("""
            QLabel {
                background-color: #f0f0f0;
                padding: 15px;
                border: 2px solid #ccc;
                border-radius: 10px;
                color: #333;
            }
        """)
        recognition_layout.addWidget(self.recognition_label)
        
        self.confidence_label = QLabel("置信度: --")
        self.confidence_label.setAlignment(Qt.AlignCenter)
        recognition_layout.addWidget(self.confidence_label)
        
        # OCR状态
        ocr_status = "✅ OCR可用" if OCR_AVAILABLE else "❌ OCR不可用"
        self.ocr_status_label = QLabel(f"OCR状态: {ocr_status}")
        recognition_layout.addWidget(self.ocr_status_label)
        
        control_layout.addWidget(recognition_group)
        
        # 将控制面板添加到垂直布局
        vertical_layout.addWidget(control_widget)
        
        # 将垂直布局添加到中央部件
        central_widget.setLayout(vertical_layout)
        
    def start_camera(self):
        """开始显示相机"""
        if self.camera_thread is None or not self.camera_thread.is_running:
            self.camera_thread = CameraThread(0)
            self.camera_thread.image_ready.connect(self.update_image)
            self.camera_thread.binary_ready.connect(self.update_binary_image)
            self.camera_thread.exposure_changed.connect(self.on_exposure_updated)
            self.camera_thread.fps_updated.connect(self.update_fps)
            self.camera_thread.number_detected.connect(self.update_recognition_result)
            self.camera_thread.start()
            
            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
            self.status_label.setText("正在显示相机图像...")
    
    def stop_camera(self):
        """停止显示相机"""
        if self.camera_thread and self.camera_thread.is_running:
            self.camera_thread.stop()
            self.camera_thread.wait()
            
            self.start_button.setEnabled(True)
            self.stop_button.setEnabled(False)
            self.status_label.setText("已停止")
    
    def on_exposure_changed(self, value):
        """曝光时间滑块变化"""
        exposure_time = float(value)  # 微秒
        if exposure_time >= 1000000:  # 大于等于1秒
            self.exposure_label.setText(f"曝光时间: {exposure_time/1000000:.2f} 秒")
        else:
            self.exposure_label.setText(f"曝光时间: {exposure_time/1000:.1f} 毫秒")
        
        # 如果相机正在运行，立即更新曝光时间
        if self.camera_thread and self.camera_thread.is_running:
            self.camera_thread.set_exposure(exposure_time)
    
    def on_exposure_updated(self, exposure_time):
        """曝光时间更新回调"""
        if exposure_time >= 1000000:  # 大于等于1秒
            self.exposure_label.setText(f"曝光时间: {exposure_time/1000000:.2f} 秒")
        else:
            self.exposure_label.setText(f"曝光时间: {exposure_time/1000:.1f} 毫秒")
    
    def set_auto_exposure(self):
        """设置自动曝光"""
        # 这里可以添加自动曝光的逻辑
        self.exposure_slider.setValue(10000)  # 重置为默认值
        self.status_label.setText("已设置为自动曝光模式")
    
    def set_short_exposure(self):
        """设置短曝光"""
        self.exposure_slider.setValue(5000)  # 5毫秒
        self.status_label.setText("已设置为短曝光模式")
    
    def set_long_exposure(self):
        """设置长曝光"""
        self.exposure_slider.setValue(300000)  # 300毫秒
        self.status_label.setText("已设置为长曝光模式")
    
    def set_ultra_long_exposure(self):
        """设置超长曝光"""
        self.exposure_slider.setValue(600000)  # 600毫秒
        self.status_label.setText("已设置为超长曝光模式")
    
    def set_extreme_exposure(self):
        """设置极长曝光"""
        self.exposure_slider.setValue(900000)  # 900毫秒
        self.status_label.setText("已设置为极长曝光模式")
    
    def update_recognition_result(self, number, confidence):
        """更新数字识别结果"""
        if number:
            self.recognition_label.setText(f"识别数字: {number}")
            self.confidence_label.setText(f"置信度: {confidence:.2f}")
            
            # 根据置信度设置颜色
            if confidence >= 0.8:
                self.recognition_label.setStyleSheet("""
                    QLabel {
                        background-color: #d4edda;
                        padding: 15px;
                        border: 2px solid #28a745;
                        border-radius: 10px;
                        color: #155724;
                    }
                """)
            elif confidence >= 0.6:
                self.recognition_label.setStyleSheet("""
                    QLabel {
                        background-color: #fff3cd;
                        padding: 15px;
                        border: 2px solid #ffc107;
                        border-radius: 10px;
                        color: #856404;
                    }
                """)
            else:
                self.recognition_label.setStyleSheet("""
                    QLabel {
                        background-color: #f8d7da;
                        padding: 15px;
                        border: 2px solid #dc3545;
                        border-radius: 10px;
                        color: #721c24;
                    }
                """)
        else:
            self.recognition_label.setText("未识别到数字")
            self.confidence_label.setText("置信度: --")
            self.recognition_label.setStyleSheet("""
                QLabel {
                    background-color: #f0f0f0;
                    padding: 15px;
                    border: 2px solid #ccc;
                    border-radius: 10px;
                    color: #333;
                }
            """)
    
    def update_fps(self, fps):
        """更新帧率显示"""
        self.fps_label.setText(f"FPS: {fps:.1f}")
        
        # 根据帧率设置颜色
        if fps >= 25:
            self.fps_label.setStyleSheet("""
                QLabel {
                    background-color: rgba(0, 255, 0, 0.8);
                    color: white;
                    padding: 5px 10px;
                    border-radius: 5px;
                    font-weight: bold;
                    font-size: 12px;
                }
            """)
            self.performance_label.setText("性能: 优秀")
        elif fps >= 15:
            self.fps_label.setStyleSheet("""
                QLabel {
                    background-color: rgba(255, 165, 0, 0.8);
                    color: white;
                    padding: 5px 10px;
                    border-radius: 5px;
                    font-weight: bold;
                    font-size: 12px;
                }
            """)
            self.performance_label.setText("性能: 良好")
        else:
            self.fps_label.setStyleSheet("""
                QLabel {
                    background-color: rgba(255, 0, 0, 0.8);
                    color: white;
                    padding: 5px 10px;
                    border-radius: 5px;
                    font-weight: bold;
                    font-size: 12px;
                }
            """)
            self.performance_label.setText("性能: 需要优化")
    
    def on_fps_limit_changed(self, text):
        """帧率限制变化"""
        if text == "无限制":
            self.fps_limit = None
        else:
            self.fps_limit = float(text.split()[0])  # 提取数字
        self.status_label.setText(f"帧率限制: {text}")
    
    def on_binary_method_changed(self, text):
        """二值化方法变化"""
        method_map = {
            "自适应阈值": "adaptive",
            "OTSU": "otsu", 
            "简单阈值": "simple",
            "Canny边缘": "canny"
        }
        self.binary_method = method_map.get(text, "adaptive")
        
        # 更新相机线程的二值化方法
        if self.camera_thread and self.camera_thread.is_running:
            self.camera_thread.set_binary_method(self.binary_method)
        
        self.status_label.setText(f"二值化方法: {text}")
    
    def update_image(self, img):
        """更新图像显示"""
        if img is None:
            return
        
        # 帧率限制检查
        if self.fps_limit:
            current_time = time.time()
            min_interval = 1.0 / self.fps_limit
            if current_time - self.last_frame_time < min_interval:
                return  # 跳过这一帧
            self.last_frame_time = current_time
            
        # 确保图像是3通道的
        if len(img.shape) == 2:
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        
        # 调整图像大小以适应显示区域
        if len(img.shape) == 3:
            height, width, channel = img.shape
        else:
            height, width = img.shape
            channel = 1
            
        max_width = self.image_label.width() - 10
        max_height = self.image_label.height() - 10
        
        if width > max_width or height > max_height:
            scale = min(max_width / width, max_height / height)
            new_width = int(width * scale)
            new_height = int(height * scale)
            img = cv2.resize(img, (new_width, new_height))
            if len(img.shape) == 3:
                height, width, channel = img.shape
            else:
                height, width = img.shape
                channel = 1
        
        # 转换为QImage
        if channel == 3:
            bytes_per_line = 3 * width
            q_img = QImage(img.data, width, height, bytes_per_line, QImage.Format_RGB888)
        else:
            bytes_per_line = width
            q_img = QImage(img.data, width, height, bytes_per_line, QImage.Format_Grayscale8)
        
        # 显示图像
        pixmap = QPixmap.fromImage(q_img)
        self.image_label.setPixmap(pixmap)
    
    def update_binary_image(self, img):
        """更新二值化图像显示"""
        if img is None:
            return
        
        # 调整图像大小以适应显示区域
        height, width = img.shape
        max_width = self.binary_label.width() - 10
        max_height = self.binary_label.height() - 10
        
        if width > max_width or height > max_height:
            scale = min(max_width / width, max_height / height)
            new_width = int(width * scale)
            new_height = int(height * scale)
            img = cv2.resize(img, (new_width, new_height))
            height, width = img.shape
        
        # 转换为QImage - 直接使用灰度格式显示黑白图像
        bytes_per_line = width
        q_img = QImage(img.data, width, height, bytes_per_line, QImage.Format_Grayscale8)
        
        # 显示二值化图像
        pixmap = QPixmap.fromImage(q_img)
        self.binary_label.setPixmap(pixmap)
    

    
    def closeEvent(self, event):
        """关闭事件"""
        self.stop_camera()
        event.accept()

def main():
    app = QApplication(sys.argv)
    window = SimpleCameraViewer()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main() 